package com.shunli.cterminal.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.shunli.cterminal.common.QmConstant;
import com.shunli.cterminal.entity.*;
import com.shunli.cterminal.mapper.*;
import com.shunli.cterminal.model.req.*;
import com.shunli.cterminal.model.res.ExpGroupVO;
import com.shunli.cterminal.model.res.ExpRespVO;
import com.shunli.cterminal.util.BeanUtils;
import com.shunli.cterminal.util.QmLibraUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @ClassName: AbTestService
 * @Description: TODO
 * @Author: DAIYALU
 * @Date: 2025/6/5
 * @Version: 1.0
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class AbTestService {

    private final ExpMapper expMapper;
    private final ExpGroupMapper expGroupMapper;
    private final ExpUserMapper expUserMapper;
    private final LayerMapper layerMapper;
    private final StrategyMapper strategyMapper;

    public List<ExpGroupVO> requestLibra(LibraRequestReqReq reqVo) {
        log.info("requestLibra - start, reqVo:{}", reqVo);
        List<ExpGroupVO> result = new ArrayList<>();

        List<ExpDO> expList = new ArrayList<>();
        if(reqVo.getExpId()!=null){
            ExpDO expDO = expMapper.selectById(reqVo.getExpId());
            if(expDO!=null && expDO.getExpStatus().intValue()== QmConstant.LibraExpStatus.open.getStatus()){
                expList.add(expDO);
            }
        }
        else{
            ExpReq expPageReqVO = new ExpReq();
            expPageReqVO.setSceneCode(reqVo.getSceneCode());
            expPageReqVO.setSceneCodeList(reqVo.getSceneCodeList());
            expPageReqVO.setExpIdList(reqVo.getExpIdList());
            expPageReqVO.setExpStatus(QmConstant.LibraExpStatus.open.getStatus());
            List<ExpDO> expDOList = expMapper.getExpList(expPageReqVO);
            // todo 获取所有命中的实验
            if(CollectionUtil.isNotEmpty(expDOList)){
                expList.addAll(expDOList);
            }
        }
        log.info("requestLibra - info, expList:{}", expList);
        Map<String,Integer> evMap = new HashMap<>();
        if(CollectionUtil.isNotEmpty(expList)){
            List<ExpDO> hitExpList = new ArrayList<>();

            for(ExpDO expDO: expList){
                //先看有没有命中对应的流量层流量
                String layerBucketIdsStr = expDO.getLayerRateBucketIds();
                String[] bs = layerBucketIdsStr.split(",");
                Set<Integer> bset = new HashSet<>(Stream.of(bs).map(Integer::parseInt).collect(Collectors.toList()));

                int lv = QmLibraUtils.murmurHashSplit(expDO.getLayerCode()+"-"+reqVo.getId(),100).intValue();
                log.info("requestLibra - info, layerSet:{}, lv:{}", bset, lv);
                if(bset.contains(lv)){//命中流量层
                    int ev = QmLibraUtils.murmurHashSplit(expDO.getExpCode()+"-"+reqVo.getId(),100).intValue();
                    log.info("requestLibra - info, expRate:{}, ev:{}", expDO.getExpRate(), ev);
                    if(ev<=expDO.getExpRate()){
                        //命中实验
                        hitExpList.add(expDO);
                        evMap.put(expDO.getExpCode(),ev);
                    }
                }
            }
            log.info("requestLibra - info, hitExpList:{}", hitExpList);
            log.info("requestLibra - info, evMap:{}", evMap);
            if(CollectionUtil.isEmpty(hitExpList)){
                return result;
            }
            List<String> expCodeList = hitExpList.stream().map(ExpDO::getExpCode).collect(Collectors.toList());
            ExpGroupReq groupPageReqVO = new ExpGroupReq();
            groupPageReqVO.setExpCodeList(expCodeList);
            List<ExpGroupDO> expGroupDOS = expGroupMapper.queryExpGroupList(groupPageReqVO);
            for(ExpGroupDO expGroupDO: expGroupDOS){
                String expBucketIds = expGroupDO.getExpBucketIds();
                String[] bs = expBucketIds.split(",");
                Set<Integer> expBucketIdSet = new HashSet<>(Stream.of(bs).map(Integer::parseInt).collect(Collectors.toList()));
                if(evMap.containsKey(expGroupDO.getExpCode()) && expBucketIdSet.contains(evMap.get(expGroupDO.getExpCode()))){
                    ExpGroupVO vo = BeanUtils.toBean(expGroupDO, ExpGroupVO.class);;
                    result.add(vo);

                    //生成命中记录
                    ExpUserSaveReq createReqVO = new ExpUserSaveReq();
                    createReqVO.setAppId(expGroupDO.getAppId());
                    createReqVO.setExpId(expGroupDO.getExpId());
                    createReqVO.setVid(expGroupDO.getId());
                    createReqVO.setIdType(expGroupDO.getIdType());
                    createReqVO.setIdValue(reqVo.getId());
                    createReqVO.setExpCode(expGroupDO.getExpCode());
                    createReqVO.setExpGroupParam(expGroupDO.getExpGroupParam());
                    ExpUserDO expUser = BeanUtils.toBean(createReqVO, ExpUserDO.class);
                    expUserMapper.insert(expUser);
                }
            }
        }
        log.info("requestLibra - end, result:{}", result);
        return result;
    }

    public List<ExpRespVO> libraExpPage(LibraRequestReqReq req) {
        if(ObjectUtil.isNull(req)){
            return new ArrayList<>();
        }
        ExpReq expPageReqVO = new ExpReq();
        expPageReqVO.setSceneCode(req.getSceneCode());
        expPageReqVO.setExpStatus(3);
        log.info("libraExpPage - start, reqVO:{}", req);
        List<ExpDO> pageResult = expMapper.getExpList(expPageReqVO);
        List<ExpRespVO> result = BeanUtils.toBean(pageResult, ExpRespVO.class);
        if(CollectionUtil.isNotEmpty(result)) {
            //补全流量层信息
            List<String> layerCodeList = result.stream().map(ExpRespVO::getLayerCode).collect(Collectors.toList());
            List<LayerDO> layerDOList = this.getLayerByCodeList(layerCodeList);
            Map<String, LayerDO> layerDOMap = layerDOList.stream().collect(Collectors.toMap(LayerDO::getLayerCode, each -> each, (value1, value2) -> value1));
            for (ExpRespVO vo : result) {
                vo.setLayer(layerDOMap.get(vo.getLayerCode()));
            }
            //补全分组信息
            List<String> expCodeList = result.stream().map(ExpRespVO::getExpCode).collect(Collectors.toList());
            ExpGroupReq groupPageReqVO = new ExpGroupReq();
            groupPageReqVO.setExpCodeList(expCodeList);
            List<ExpGroupDO> expGroupList = expGroupMapper.queryExpGroupList(groupPageReqVO);

            //策略信息
            Map<Long, StrategyDO> strategyDOMap = new HashMap<>();
            if (CollectionUtil.isNotEmpty(expCodeList)) {
                StrategyReq strategyPageReqVO = new StrategyReq();
                strategyPageReqVO.setIds(expGroupList.stream().map(ExpGroupDO::getStrategyId).collect(Collectors.toList()));
                List<StrategyDO> strategyEventDOList = strategyMapper.getStrategyList(strategyPageReqVO);
                for (StrategyDO strategyDO : strategyEventDOList) {
                    strategyDOMap.put(strategyDO.getId(), strategyDO);
                }
            }
        }
        log.info("libraExpPage - end, result:{}", result);
        return result;
    }

    public List<LayerDO> getLayerByCodeList(List<String> codeList) {
        if(CollectionUtil.isEmpty(codeList)){
            return new ArrayList<>();
        }
        LayerPageReq pageReqVO = new LayerPageReq();
        pageReqVO.setLayerCodeList(codeList);
        return layerMapper.queryLayerList(pageReqVO);
    }
}
